package nachos.threads;

import java.util.*;

import nachos.machine.*;

/**
 * A <i>communicator</i> allows threads to synchronously exchange 32-bit
 * messages. Multiple threads can be waiting to <i>speak</i>,
 * and multiple threads can be waiting to <i>listen</i>. But there should never
 * be a time when both a speaker and a listener are waiting, because the two
 * threads can be paired off at this point.
 */
public class Communicator {
    /**
     * Allocate a new communicator.
     */
    public Communicator() {
        speakers = new LinkedList();
        listeners = new LinkedList();
        message = new HashMap();
    }

    /**
     * Wait for a thread to listen through this communicator, and then transfer
     * <i>word</i> to the listener.
     *
     * <p>
     * Does not return until this thread is paired up with a listening thread.
     * Exactly one listener should receive <i>word</i>.
     *
     * @param	word	the integer to transfer.
     */
    public void speak(int word) {
        if(listeners.isEmpty()){
            speakers.add(KThread.currentThread());
            message.put(KThread.currentThread(), word);
            KThread.sleep();
        }else{
            listeners.getFirst().awake();
            speakers.add(KThread.currentThread());
            message.put(KThread.currentThread(), word);
        }
    }

    /**
     * Wait for a thread to speak through this communicator, and then return
     * the <i>word</i> that thread passed to <tt>speak()</tt>.
     *
     * @return	the integer transferred.
     */    
    public int listen() {
        if(speakers.isEmpty()){
            listeners.add(KThread.currentThread());
            KThread.sleep();
            return message.remove(speakers.removeFirst());
        }else{
            speakers.getFirst().awake();
            return message.remove(speakers.removeFirst());
        }
    }

    private LinkedList<KThread> speakers;
    private LinkedList<KThread> listeners;
    private HashMap<KThread,Integer> message;
}